import { Body, Controller, Get, Param, Post, Patch, Delete, Query, Res, Headers, UseGuards, Req } from '@nestjs/common';
import { TrackingMongoService } from './tracking-mongo.service';
import { TrackingLoggerService } from './tracking-logger.service';
import { CreateWebsiteDto } from './dto/create-website.dto';
import { UpdateWebsiteDto } from './dto/update-website.dto';
import { TrackPageviewDto } from './dto/track-pageview.dto';
import { WebsiteQueryDto } from './dto/website-query.dto';
import { Response, Request } from 'express';
import { TokenGuard } from '../../common/guards/token.guard';
import { RolesGuard } from '../../common/guards/roles.guard';
import { Roles } from '../../common/decorators/roles.decorator';

@Controller('tracking')
export class TrackingController {
  constructor(
    private readonly trackingService: TrackingMongoService,
    private readonly trackingLogger: TrackingLoggerService,
  ) {}

  // 管理员API - 需要认证和角色
  @Post('websites')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops')
  createWebsite(@Body() createWebsiteDto: CreateWebsiteDto) {
    return this.trackingService.createWebsite(createWebsiteDto);
  }

  @Patch('websites/:id')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops')
  updateWebsite(@Param('id') id: string, @Body() updateWebsiteDto: UpdateWebsiteDto) {
    return this.trackingService.updateWebsite(id, updateWebsiteDto);
  }

  @Delete('websites/:id')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops')
  deleteWebsite(@Param('id') id: string) {
    return this.trackingService.deleteWebsite(id);
  }

  @Delete('websites/all')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops')
  deleteAllWebsites() {
    return this.trackingService.deleteAllWebsites();
  }

  @Get('websites')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getAllWebsites() {
    return this.trackingService.getAllWebsites();
  }

  @Get('websites/:id')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getWebsiteById(@Param('id') id: string) {
    return this.trackingService.getWebsiteById(id);
  }

  @Get('websites/:id/summary')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  async getWebsiteSummary(
    @Param('id') id: string,
    @Query() query: WebsiteQueryDto
  ) {
    return this.trackingService.getWebsiteSummary(id, query);
  }

  @Get('websites/:id/stats')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getWebsiteStats(
    @Param('id') id: string,
    @Query() query: WebsiteQueryDto
  ) {
    return this.trackingService.getWebsiteStats(id, query);
  }

  @Get('websites/:id/embed-code')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getEmbedCode(@Param('id') id: string) {
    return this.trackingService.getEmbedCode(id);
  }

  // 新增: 获取网站所有访问过的IP列表
  @Get('websites/:id/ips')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getWebsiteIps(@Param('id') id: string) {
    return this.trackingService.getWebsiteIps(id);
  }

  // 新增: 获取IP访问详情
  @Get('visits/ip/:ip')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getIpVisits(
    @Param('ip') ip: string,
    @Query('websiteId') websiteId?: string,
    @Query('startDate') startDate?: string,
    @Query('endDate') endDate?: string
  ) {
    return this.trackingService.getIpVisits(
      ip, 
      websiteId,
      startDate,
      endDate
    );
  }

  // 新增: 获取会话详情
  @Get('visits/session/:sessionId')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getSessionDetails(@Param('sessionId') sessionId: string) {
    return this.trackingService.getSessionDetails(sessionId);
  }

  // 提取真实IP地址
  private extractRealIp(req: Request): string {
    // 优先级：X-Forwarded-For > X-Real-IP > CF-Connecting-IP > req.ip > connection.remoteAddress
    
    // 1. 检查 X-Forwarded-For 头（最常见）
    const xForwardedFor = req.headers['x-forwarded-for'];
    if (xForwardedFor) {
      // X-Forwarded-For 可能是多个IP，取第一个（真实客户端IP）
      const ips = Array.isArray(xForwardedFor) 
        ? xForwardedFor[0] 
        : xForwardedFor;
      const firstIp = ips.split(',')[0].trim();
      // 过滤掉本地地址
      if (firstIp && firstIp !== '::1' && firstIp !== '127.0.0.1' && !firstIp.startsWith('::ffff:127.0.0.1')) {
        return firstIp;
      }
    }
    
    // 2. 检查 X-Real-IP 头
    const xRealIp = req.headers['x-real-ip'];
    if (xRealIp) {
      const realIp = Array.isArray(xRealIp) ? xRealIp[0] : xRealIp;
      if (realIp && realIp !== '::1' && realIp !== '127.0.0.1' && !realIp.startsWith('::ffff:127.0.0.1')) {
        return realIp;
      }
    }
    
    // 3. 检查 Cloudflare 的 CF-Connecting-IP
    const cfConnectingIp = req.headers['cf-connecting-ip'];
    if (cfConnectingIp) {
      const cfIp = Array.isArray(cfConnectingIp) ? cfConnectingIp[0] : cfConnectingIp;
      if (cfIp) {
        return cfIp;
      }
    }
    
    // 4. 检查 X-Client-IP
    const xClientIp = req.headers['x-client-ip'];
    if (xClientIp) {
      const clientIp = Array.isArray(xClientIp) ? xClientIp[0] : xClientIp;
      if (clientIp && clientIp !== '::1' && clientIp !== '127.0.0.1') {
        return clientIp;
      }
    }
    
    // 5. 如果启用了 trust proxy，req.ip 会自动解析
    if (req.ip && req.ip !== '::1' && req.ip !== '127.0.0.1' && !req.ip.startsWith('::ffff:127.0.0.1')) {
      return req.ip;
    }
    
    // 6. 降级：从 connection 获取
    const remoteAddress = req.socket?.remoteAddress;
    if (remoteAddress) {
      // 处理 IPv6 映射的 IPv4 地址 (::ffff:127.0.0.1 -> 127.0.0.1)
      let ip = remoteAddress.replace(/^::ffff:/, '');
      // 如果是本地地址，尝试从 Origin 头推断（跨域请求的场景）
      if (ip === '::1' || ip === '127.0.0.1') {
        const origin = req.headers['origin'];
        if (origin) {
          // 记录日志以便调试
          console.log(`[IP Debug] 本地访问，Origin: ${origin}, RemoteAddress: ${remoteAddress}`);
        }
      }
      return ip;
    }
    
    // 最后的降级方案
    return 'unknown';
  }

  // 公共API - 不需要认证
  @Post('pageview')
  async trackPageviewPost(
    @Body() trackPageviewDto: TrackPageviewDto, 
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
    @Res() res: Response
  ) {
    const ip = this.extractRealIp(req);
    return this.handlePageview(trackPageviewDto, ip, userAgent, res);
  }

  @Get('pageview')
  async trackPageviewGet(
    @Query() query: any,
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
    @Res() res: Response
  ) {
    // 将查询参数转换为DTO格式
    const trackPageviewDto: TrackPageviewDto = {
      trackingId: query.trackingId,
      url: query.url,
      title: query.title,
      referrer: query.referrer,
      sessionId: query.sessionId,
      customData: query.customData ? JSON.parse(query.customData) : {}
    };
    
    const ip = this.extractRealIp(req);
    return this.handlePageview(trackPageviewDto, ip, userAgent, res);
  }

  private async handlePageview(
    trackPageviewDto: TrackPageviewDto, 
    ip: string, 
    userAgent: string, 
    res: Response
  ) {
    try {
      // 调试：如果是本地IP，记录详细信息
      if (ip === '::1' || ip === '127.0.0.1') {
        console.log(`[IP Debug] 检测到本地IP: ${ip}`);
        console.log(`[IP Debug] 请求头:`, {
          'x-forwarded-for': res.req?.headers['x-forwarded-for'],
          'x-real-ip': res.req?.headers['x-real-ip'],
          'cf-connecting-ip': res.req?.headers['cf-connecting-ip'],
          'x-client-ip': res.req?.headers['x-client-ip'],
          origin: res.req?.headers['origin'],
          referer: res.req?.headers['referer'],
          'remote-address': res.req?.socket?.remoteAddress,
          'req.ip': res.req?.ip
        });
      }
      
      // 记录页面访问发送日志
      this.trackingLogger.logPageviewSent(
        trackPageviewDto.trackingId,
        trackPageviewDto.url,
        ip,
        userAgent,
        trackPageviewDto.sessionId || 'unknown',
        trackPageviewDto
      );

      const pageview = await this.trackingService.trackPageview(trackPageviewDto, ip, userAgent);
      
      // 返回1x1像素的GIF图片
      res.setHeader('Content-Type', 'image/gif');
      res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
      res.setHeader('Pragma', 'no-cache');
      res.setHeader('Expires', '0');
      
      // 1x1透明GIF的base64编码
      const gifData = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');
      res.send(gifData);
    } catch (error) {
      // 记录错误日志
      this.trackingLogger.logError(
        trackPageviewDto.trackingId,
        trackPageviewDto.url,
        ip,
        userAgent,
        trackPageviewDto.sessionId || 'unknown',
        'PAGEVIEW_PROCESSING',
        error,
        trackPageviewDto
      );
      
      // 即使出错也返回图片，避免客户端报错
      res.setHeader('Content-Type', 'image/gif');
      const gifData = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');
      res.send(gifData);
    }
  }

  @Post('script-loaded')
  async trackScriptLoadedPost(
    @Body() trackPageviewDto: TrackPageviewDto, 
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
    @Res() res: Response
  ) {
    const ip = this.extractRealIp(req);
    return this.handleScriptLoaded(trackPageviewDto, ip, userAgent, res);
  }

  @Get('script-loaded')
  async trackScriptLoadedGet(
    @Query() query: any,
    @Req() req: Request,
    @Headers('user-agent') userAgent: string,
    @Res() res: Response
  ) {
    // 将查询参数转换为DTO格式
    const trackPageviewDto: TrackPageviewDto = {
      trackingId: query.trackingId,
      url: query.url,
      title: query.title,
      referrer: query.referrer,
      sessionId: query.sessionId,
      customData: query.customData ? JSON.parse(query.customData) : {}
    };
    
    const ip = this.extractRealIp(req);
    return this.handleScriptLoaded(trackPageviewDto, ip, userAgent, res);
  }

  private async handleScriptLoaded(
    trackPageviewDto: TrackPageviewDto, 
    ip: string, 
    userAgent: string, 
    res: Response
  ) {
    try {
      // 记录脚本加载日志
      this.trackingLogger.logScriptLoaded(
        trackPageviewDto.trackingId,
        trackPageviewDto.url,
        ip,
        userAgent,
        trackPageviewDto.sessionId || 'unknown',
        trackPageviewDto
      );

      // 返回1x1像素的GIF图片
      res.setHeader('Content-Type', 'image/gif');
      res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
      res.setHeader('Pragma', 'no-cache');
      res.setHeader('Expires', '0');
      
      const gifData = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');
      res.send(gifData);
    } catch (error) {
      // 记录错误日志
      this.trackingLogger.logError(
        trackPageviewDto.trackingId,
        trackPageviewDto.url,
        ip,
        userAgent,
        trackPageviewDto.sessionId || 'unknown',
        'SCRIPT_LOADED_PROCESSING',
        error,
        trackPageviewDto
      );
      
      // 即使出错也返回图片
      res.setHeader('Content-Type', 'image/gif');
      const gifData = Buffer.from('R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7', 'base64');
      res.send(gifData);
    }
  }

  @Get('script.js')
  getTrackingScript(@Res() res: Response) {
    const script = this.trackingService.getTrackingScript();
    res.setHeader('Content-Type', 'application/javascript');
    res.setHeader('Cache-Control', 'public, max-age=3600'); // 缓存1小时
    res.send(script);
  }

  @Get('logs/stats')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getLogStats() {
    return this.trackingLogger.getTodayStats();
  }

  @Get('logs/business-loop/:trackingId')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  getBusinessLoopLogs(
    @Param('trackingId') trackingId: string,
    @Query('date') date?: string
  ) {
    return this.trackingLogger.getBusinessLoopByTrackingId(trackingId, date);
  }

  @Get('logs/business-loop/:trackingId/integrity')
  @UseGuards(TokenGuard, RolesGuard)
  @Roles('admin', 'devops', 'viewer')
  checkBusinessLoopIntegrity(
    @Param('trackingId') trackingId: string,
    @Query('date') date?: string
  ) {
    return this.trackingLogger.checkBusinessLoopIntegrity(trackingId, date);
  }
} 